Multiple Charts Example

This example demonstrates how to combine multiple chart types in a single chart context, dynamically display annotations based on user interaction, and customize appearance and interactivity using chart overlays.

Example Code

1const data = [
2  { sales: 1200, year: '2020', growth: 0.14, },
3  { sales: 1400, year: '2021', growth: 0.16, },
4  { sales: 2000, year: '2022', growth: 0.42, },
5  { sales: 2500, year: '2023', growth: 0.25, },
6  { sales: 3600, year: '2024', growth: 0.44, },
7]
8
9function Example() {
10  const [chartSelection, setChartSelection] = useState<string | null>()
11  const selectedItem = useMemo(() => {
12    if (chartSelection == null) {
13      return null
14    }
15    return data.find(item => item.year === chartSelection)
16  }, [chartSelection])
17
18  return <NavigationStack>
19    <VStack
20      navigationTitle={"Multiple Charts"}
21      navigationBarTitleDisplayMode={"inline"}
22    >
23      <Text>
24        Press and move on the chart to view the details.
25      </Text>
26      <Chart
27        frame={{
28          height: 300,
29        }}
30        chartXSelection={{
31          value: chartSelection,
32          onChanged: setChartSelection,
33          valueType: "string"
34        }}
35      >
36        <LineChart
37          marks={data.map(item => ({
38            label: item.year,
39            value: item.sales,
40            interpolationMethod: "catmullRom",
41            symbol: "circle",
42          }))}
43        />
44        <AreaChart
45          marks={data.map(item => ({
46            label: item.year,
47            value: item.sales,
48            interpolationMethod: "catmullRom",
49            foregroundStyle: ["rgba(255,100,0,1)", "rgba(255,100,0,0.2)"]
50          }))}
51        />
52        {selectedItem != null
53          ? <RuleLineForLabelChart
54            marks={[{
55              label: selectedItem.year,
56              foregroundStyle: { color: "gray", opacity: 0.5 },
57              annotation: {
58                position: "top",
59                overflowResolution: {
60                  x: "fit",
61                  y: "disabled"
62                },
63                content: <ZStack
64                  padding
65                  background={
66                    <RoundedRectangle
67                      cornerRadius={4}
68                      fill={"regularMaterial"}
69                    />
70                  }
71                >
72                  <Text
73                    foregroundStyle={"white"}
74                  >Sales: {selectedItem.sales}</Text>
75                </ZStack>
76              }
77            }]}
78          />
79          : null}
80      </Chart>
81    </VStack>
82  </NavigationStack>
83}

Overview

The example uses the following components together:

  • LineChart: Plots discrete points and connects them with curved lines.
  • AreaChart: Fills the area under a line graph, visually indicating magnitude.
  • RuleLineForLabelChart: Draws a reference line at the selected label and overlays a custom annotation.
  • chartXSelection: Enables user interaction by tracking X-axis selection.

Data Format

The dataset used represents yearly sales performance:

1const data = [
2  { sales: 1200, year: '2020', growth: 0.14 },
3  { sales: 1400, year: '2021', growth: 0.16 },
4  { sales: 2000, year: '2022', growth: 0.42 },
5  { sales: 2500, year: '2023', growth: 0.25 },
6  { sales: 3600, year: '2024', growth: 0.44 },
7]

Each entry includes:

  • sales: Numeric value to be plotted
  • year: Used as the label on the X-axis
  • growth: Additional metric (not directly visualized here)

Key Features

Chart Selection

1chartXSelection={{
2  value: chartSelection,
3  onChanged: setChartSelection,
4  valueType: "string"
5}}
  • Enables users to tap or drag on the chart to select a point based on its label (year).
  • Triggers the setChartSelection callback to update the selected year.

LineChart

1<LineChart
2  marks={data.map(item => ({
3    label: item.year,
4    value: item.sales,
5    interpolationMethod: "catmullRom",
6    symbol: "circle",
7  }))}
8/>
  • Plots sales values with labeled X-axis.
  • Uses "catmullRom" for smooth curves between points.
  • Displays circular symbols for each point.

AreaChart

1<AreaChart
2  marks={data.map(item => ({
3    label: item.year,
4    value: item.sales,
5    interpolationMethod: "catmullRom",
6    foregroundStyle: ["rgba(255,100,0,1)", "rgba(255,100,0,0.2)"]
7  }))}
8/>
  • Overlays a filled area beneath the line, enhancing visual weight.
  • Uses a two-stop gradient from solid to transparent orange.

RuleLineForLabelChart (Dynamic Annotation)

1<RuleLineForLabelChart
2  marks={[{
3    label: selectedItem.year,
4    foregroundStyle: { color: "gray", opacity: 0.5 },
5    annotation: {
6      position: "top",
7      overflowResolution: { x: "fit", y: "disabled" },
8      content: <ZStack
9        padding
10        background={<RoundedRectangle cornerRadius={4} fill={"regularMaterial"} />}
11      >
12        <Text foregroundStyle={"white"}>Sales: {selectedItem.sales}</Text>
13      </ZStack>
14    }
15  }]}
16/>
  • Shows a vertical gray reference line at the selected year.
  • Displays a floating tooltip with the sales value in a styled background.
  • Uses ZStack and RoundedRectangle to build a custom annotation view.

User Interaction Flow

  1. The user touches the chart.
  2. The closest label (year) is selected and passed to chartSelection.
  3. selectedItem is computed using useMemo.
  4. A rule line is rendered at the selected label.
  5. A floating annotation displays detailed data (e.g., Sales: 2500).

Conclusion

This example demonstrates how to:

  • Combine multiple charts (LineChart, AreaChart, RuleLineForLabelChart) within a single <Chart> container.
  • Use chartXSelection to enable touch-based exploration.
  • Render contextual annotations that enhance data storytelling.
  • Apply modern styling using gradient fills, translucent overlays, and SwiftUI-inspired layout components.

This pattern is ideal for dashboards and interactive reports where data insight and responsiveness are key.